﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using HandyControl.Data;


namespace HandyControl.Controls;

public class LoadingCircle : LoadingBase
{
    public static readonly DependencyProperty DotOffSetProperty = DependencyProperty.Register(
        nameof(DotOffSet), typeof(double), typeof(LoadingCircle),
        new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsRender));

    public double DotOffSet
    {
        get => (double) GetValue(DotOffSetProperty);
        set => SetValue(DotOffSetProperty, value);
    }

    public static readonly DependencyProperty NeedHiddenProperty = DependencyProperty.Register(
        nameof(NeedHidden), typeof(bool), typeof(LoadingCircle),
        new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));

    public bool NeedHidden
    {
        get => (bool) GetValue(NeedHiddenProperty);
        set => SetValue(NeedHiddenProperty, ValueBoxes.BooleanBox(value));
    }

    static LoadingCircle()
    {
        DotSpeedProperty.OverrideMetadata(typeof(LoadingCircle),
            new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));
        DotDelayTimeProperty.OverrideMetadata(typeof(LoadingCircle),
            new FrameworkPropertyMetadata(220.0, FrameworkPropertyMetadataOptions.AffectsRender));
    }

    protected sealed override void UpdateDots()
    {
        var dotCount = DotCount;
        var dotInterval = DotInterval;
        var dotSpeed = DotSpeed;
        var dotDelayTime = DotDelayTime;
        var needHidden = NeedHidden;

        if (dotCount < 1) return;
        PrivateCanvas.Children.Clear();

        //定义动画
        Storyboard = new Storyboard
        {
            RepeatBehavior = RepeatBehavior.Forever
        };

        //创建圆点
        for (var i = 0; i < dotCount; i++)
        {
            var border = CreateBorder(i, dotInterval, needHidden);

            var framesMove = new DoubleAnimationUsingKeyFrames
            {
                BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
            };

            var subAngle = -dotInterval * i;

            //开始位置
            var frame0 = new LinearDoubleKeyFrame
            {
                Value = 0 + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
            };

            //开始位置到第一次匀速开始
            var frame1 = new EasingDoubleKeyFrame
            {
                EasingFunction = new PowerEase
                {
                    EasingMode = EasingMode.EaseOut
                },
                Value = 180 + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (0.75 / 7)))
            };

            //第一次匀速开始到第一次匀速结束
            var frame2 = new LinearDoubleKeyFrame
            {
                Value = 180 + DotOffSet + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (2.75 / 7)))
            };

            //第一次匀速结束到匀加速结束
            var frame3 = new EasingDoubleKeyFrame
            {
                EasingFunction = new PowerEase
                {
                    EasingMode = EasingMode.EaseIn
                },
                Value = 360 + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (3.5 / 7)))
            };

            //匀加速结束到匀减速结束
            var frame4 = new EasingDoubleKeyFrame
            {
                EasingFunction = new PowerEase
                {
                    EasingMode = EasingMode.EaseOut
                },
                Value = 540 + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (4.25 / 7)))
            };

            //匀减速结束到第二次匀速结束
            var frame5 = new LinearDoubleKeyFrame
            {
                Value = 540 + DotOffSet + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (6.25 / 7)))
            };

            //第二次匀速结束到匀加速结束
            var frame6 = new EasingDoubleKeyFrame
            {
                EasingFunction = new PowerEase
                {
                    EasingMode = EasingMode.EaseIn
                },
                Value = 720 + subAngle,
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
            };

            framesMove.KeyFrames.Add(frame0);
            framesMove.KeyFrames.Add(frame1);
            framesMove.KeyFrames.Add(frame2);
            framesMove.KeyFrames.Add(frame3);
            framesMove.KeyFrames.Add(frame4);
            framesMove.KeyFrames.Add(frame5);
            framesMove.KeyFrames.Add(frame6);

            Storyboard.SetTarget(framesMove, border);
            Storyboard.SetTargetProperty(framesMove, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
            Storyboard.Children.Add(framesMove);

            if (NeedHidden)
            {
                //隐藏一段时间
                var frame7 = new DiscreteObjectKeyFrame
                {
                    Value = Visibility.Collapsed,
                    KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
                };

                var frame8 = new DiscreteObjectKeyFrame
                {
                    Value = Visibility.Collapsed,
                    KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed + 0.4))
                };

                var frame9 = new DiscreteObjectKeyFrame
                {
                    Value = Visibility.Visible,
                    KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
                };
                var framesVisibility = new ObjectAnimationUsingKeyFrames
                {
                    BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
                };
                framesVisibility.KeyFrames.Add(frame9);
                framesVisibility.KeyFrames.Add(frame7);
                framesVisibility.KeyFrames.Add(frame8);
                Storyboard.SetTarget(framesVisibility, border);
                Storyboard.SetTargetProperty(framesVisibility, new PropertyPath("(UIElement.Visibility)"));
                Storyboard.Children.Add(framesVisibility);
            }
            PrivateCanvas.Children.Add(border);
        }

        Storyboard.Begin();
        if (!IsRunning)
        {
            Storyboard.Pause();
        }
    }

    private Border CreateBorder(int index, double dotInterval, bool needHidden)
    {
        var ellipse = CreateEllipse(index);
        ellipse.HorizontalAlignment = HorizontalAlignment.Center;
        ellipse.VerticalAlignment = VerticalAlignment.Bottom;
        var rt = new RotateTransform
        {
            Angle = -dotInterval * index
        };
        var myTransGroup = new TransformGroup();
        myTransGroup.Children.Add(rt);
        var border = new Border
        {
            RenderTransformOrigin = new Point(0.5, 0.5),
            RenderTransform = myTransGroup,
            Child = ellipse,
            Visibility = needHidden ? Visibility.Collapsed : Visibility.Visible
        };
        border.SetBinding(WidthProperty, new Binding("Width") { Source = this });
        border.SetBinding(HeightProperty, new Binding("Height") { Source = this });

        return border;
    }
}
